package cn.net.yugu.doraemon.scheduler.util;

import java.nio.charset.StandardCharsets;
import java.util.Objects;

import com.google.common.hash.Hashing;

/**
 * 常用分片方法
 *
 * @author xiangzr
 * @version 2023/10/12 8:55:25
 */
public class ShardingUtils {

    /**
     * 是否为当前分片的执行数据
     *
     * @param sliceKey   分片键
     * @param shardIndex 分片序列
     * @param shardTotal 分片  总数
     * @return
     */
    public static boolean isCurrentSlice(String sliceKey, int shardIndex, int shardTotal) {

        if (shardTotal == 1 || shardIndex == -1) {
            return true;
        }
        Objects.requireNonNull(sliceKey, "input sliceKey cannot be null!");
        final int hashCode = Hashing.murmur3_32_fixed().hashString(sliceKey, StandardCharsets.UTF_8)
                .asInt();
        return hit(shardIndex, shardTotal, hashCode);

    }

    /**
     * 是否为当前分片的执行数据
     *
     * @param sliceKey   分片键
     * @param shardIndex 分片序列
     * @param shardTotal 分片  总数
     * @return
     */
    public static boolean isCurrentSlice(Integer sliceKey, int shardIndex, int shardTotal) {

        if (shardTotal == 1 || shardIndex == -1) {
            return true;
        }

        Objects.requireNonNull(sliceKey, "input sliceKey cannot be null!");

        final int hashCode = Hashing.murmur3_32_fixed().hashInt(sliceKey)
                .asInt();
        return hit(shardIndex, shardTotal, hashCode);
    }

    /**
     * 是否为当前分片的执行数据
     *
     * @param sliceKey   分片键
     * @param shardIndex 分片序列
     * @param shardTotal 分片  总数
     * @return
     */
    public static boolean isCurrentSlice(Long sliceKey, int shardIndex, int shardTotal) {

        if (shardTotal == 1 || shardIndex == -1) {
            return true;
        }

        Objects.requireNonNull(sliceKey, "input sliceKey cannot be null!");

        final int hashCode = Hashing.murmur3_32_fixed().hashLong(sliceKey)
                .asInt();
        return hit(shardIndex, shardTotal, hashCode);

    }

    private static boolean hit(int shardIndex, int shardTotal, int hashCode) {
        return Math.abs(hashCode) % shardTotal == shardIndex;
    }
}
